﻿using HelloWorld.RobotFights;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace RobotsFight.RobotImplementation
{
    public class VadimRobot : Robot
    {
        private Array2DCoordinateStorage _pastCoordinates;
        private int circleStepCourse = 1;
        private int circleStepsCount = 0;
        private int nogoStep = 1;

        public VadimRobot(String name, ConsoleColor color)
        {
            _name = name;
            _color = color;
            _pastCoordinates = new Array2DCoordinateStorage (Console.BufferWidth, Console.BufferHeight);            
        }

        public override void DoStep(Func<int, int, Robot, int> checkEmpty)
        { 
            if (_pastCoordinates.IsRobotBlocked(x, y, checkEmpty(x + 1, y, this) != 0, checkEmpty(x, y + 1, this) != 0))
            {
                Unblock(x, y, checkEmpty);
            }
            int courseSin = 1;
            int failedStepsCount = 0;
            int currX = x; int currY = y;
            do
            {
                if (failedStepsCount > 0)    { x = currX; y = currY;     }
                if (failedStepsCount > 30)   { Unblock(x, y, checkEmpty);}
                if (courseSin > 4)           { courseSin = 1;            }
                if (circleStepsCount < 400)  { DoCircleStep();           } //первые n шагов идет по кругу из центра
                else                         { DoSinusStep(courseSin);   } //далее идет по синусоиде по каждой ячейке
                
                courseSin++;
                failedStepsCount++;                
            }
            while (_pastCoordinates.HasBeenAtCoordinate(this.x, this.y) || checkEmpty(x, y, this) != 0 || this.x == currX & this.y == currY);
            _pastCoordinates.AddCordinate(this.x, this.y);
        }

        public void DoSinusStep(int course)
        {            
            switch (course)
            {
                case 1: NewMoveLeft(); break;
                case 2: NewMoveTop(); break;
                case 3: MoveRight(); break;
                case 4: MoveBottom(); break;
            }            
        }

        public void DoRandomStep()
        {
            Random rnd = new Random();
            int course = rnd.Next(1, 5);
            switch (course)
            {
                case 1: NewMoveLeft(); break;
                case 2: NewMoveTop(); break;
                case 3: MoveRight(); break;
                case 4: MoveBottom(); break;
            }
        }

        public void DoCircleStep()
        {
            if (circleStepCourse > 4) { circleStepCourse = 1; }
            switch (circleStepCourse)
            {
                case 1: NewMoveLeft(); break;
                case 2: NewMoveTop(); break;
                case 3: MoveRight(); break;
                case 4: MoveBottom(); break;
            }
            circleStepCourse++;
            circleStepsCount++;
        }
  
        private void Unblock(int x, int y, Func<int, int, Robot, int> checkEmpty)
        {
            for (int step = 1; true; step++)
            {
                if (!_pastCoordinates.HasBeenAtCoordinate(x - step, y) && checkEmpty(x-1,y,this) == 0 && checkEmpty(x-step,y,this) == 0)
                {
                    //to the left
                    _pastCoordinates.FreeRobot(x, y, Direction.Left);
                    break;
                }
                if (!_pastCoordinates.HasBeenAtCoordinate(x, y - step) && checkEmpty(x, y - 1, this) == 0 && checkEmpty(x, y - step, this) == 0)
                {
                    //above
                    _pastCoordinates.FreeRobot(x, y, Direction.Top);
                    break;
                }
                if (!_pastCoordinates.HasBeenAtCoordinate(x, y + step) && checkEmpty(x, y + 1, this) == 0 && checkEmpty(x, y + step, this) == 0)
                {
                    //below
                    _pastCoordinates.FreeRobot(x, y, Direction.Bottom);
                    break;
                }
                if (!_pastCoordinates.HasBeenAtCoordinate(x + step, y) && checkEmpty(x + 1, y, this) == 0 && checkEmpty(x + step, y, this) == 0)
                {
                    //to the right
                    _pastCoordinates.FreeRobot(x, y, Direction.Right);
                    break;
                }
                if (step > Console.BufferHeight) //когда замкнулся в углу
                {
                    if (checkEmpty(x + nogoStep, y, this) == 0)
                    { _pastCoordinates.FreeRobot(x + nogoStep - 1, y, Direction.Right); }
                    if (checkEmpty(x - nogoStep, y, this) == 0)
                    { _pastCoordinates.FreeRobot(x - nogoStep + 1, y, Direction.Left); }
                    if (checkEmpty(x, y + nogoStep, this) == 0)
                    { _pastCoordinates.FreeRobot(x, y + nogoStep - 1, Direction.Bottom); }
                    if (checkEmpty(x, y - nogoStep, this) == 0)
                    { _pastCoordinates.FreeRobot(x, y - nogoStep + 1, Direction.Top); }
                    nogoStep++;
                    break;
                }
            }
        }

        private void NewMoveLeft()
        {
            this.MoveLeft();
            this.x = Math.Max(x, 0);
        }

        private void NewMoveTop()
        {
            this.MoveTop();
            this.y = Math.Max(y, 0);
        }
                
    }
}